/*----------------------------------------------------------------------------*\
|
|						Public Interface to Muse Technology
|
|							     www.Muse.com
| Author : SunJun 
| Email : sundoom@msn.com
\*----------------------------------------------------------------------------*/

//////////////////////////////////////////////////////////////////////////
// $Id: Matrix.h,v 1.1 2008/12/20 12:20:35 sunjun Exp $
//////////////////////////////////////////////////////////////////////////

#ifndef __Matrix__
#define __Matrix__

//////////////////////////////////////////////////////////////////////////

#if defined __cplusplus

//////////////////////////////////////////////////////////////////////////

#include <Muse.h>

//////////////////////////////////////////////////////////////////////////

NAMESPACE_BEGIN

//////////////////////////////////////////////////////////////////////////

	class API Matrix
	{
    public:
        INLINE Matrix();

        INLINE Matrix( const Matrix& mat);

        INLINE explicit Matrix( F32 const * const ptr );

        INLINE explicit Matrix( const Quaternion& quat );

        INLINE Matrix( F32 a00, F32 a01, F32 a02, F32 a03,
					   F32 a10, F32 a11, F32 a12, F32 a13,
					   F32 a20, F32 a21, F32 a22, F32 a23,
					   F32 a30, F32 a31, F32 a32, F32 a33);
        
        INLINE BOOL operator == (const Matrix& m) const;

        INLINE BOOL operator != (const Matrix& m) const;

        INLINE F32& operator()(I32 row, I32 col);

        INLINE F32 operator()(I32 row, I32 col) const;

        INLINE Matrix& operator = (const Matrix& rhs);

        INLINE VOID set(const Matrix& rhs);
        INLINE VOID set(F32 const * const ptr);
        INLINE VOID set(F32 a00, F32 a01, F32 a02,F32 a03,
						F32 a10, F32 a11, F32 a12,F32 a13,
						F32 a20, F32 a21, F32 a22,F32 a23,
						F32 a30, F32 a31, F32 a32,F32 a33);
                  
        INLINE F32 * ptr();
        INLINE const F32 * ptr() const;

		// identity
        INLINE BOOL isIdentity() const;
        INLINE VOID identity();

		// scale
		INLINE VOID setScale( const Vector3& );
        INLINE VOID setScale( F32, F32, F32 );
		INLINE Vector3 getScale() const;
        
		// translate 
        INLINE VOID setTranslate( const Vector3& );
        INLINE VOID setTranslate( F32, F32, F32 );
		INLINE Vector3 getTranslate() const;

        // rotate 
        INLINE VOID setRotate( const Vector3& from, const Vector3& to );
        INLINE VOID setRotate( F32 angle, const Vector3& axis );
        INLINE VOID setRotate( F32 angle, F32 x, F32 y, F32 z );        
        INLINE VOID setRotate( F32 angle1, const Vector3& axis1, F32 angle2, const Vector3& axis2, F32 angle3, const Vector3& axis3 );
		INLINE VOID setRotate( const Quaternion& );
		INLINE Quaternion getRotate() const;

		// basic matrix multiplication, our workhorse methods.
        INLINE VOID mult( const Matrix&, const Matrix& );
        INLINE VOID preMult( const Matrix& );
        INLINE VOID postMult( const Matrix& );	
		
        // Optimized version of preMult(translate(v));
        INLINE VOID preMultTranslate( const Vector3& v );
        // Optimized version of postMult(translate(v));
        INLINE VOID postMultTranslate( const Vector3& v );
		
        // Optimized version of preMult(scale(v));
        INLINE VOID preMultScale( const Vector3& v );
        // Optimized version of postMult(scale(v));
        INLINE VOID postMultScale( const Vector3& v );
		
        // Optimized version of preMult(rotate(q));
        INLINE VOID preMultRotate( const Quaternion& q );
        // Optimized version of postMult(rotate(q));
        INLINE VOID postMultRotate( const Quaternion& q );
		
		INLINE VOID operator *= ( const Matrix& other );
		
        INLINE Matrix operator * ( const Matrix &m ) const;

		// invert the matrix rhs
        INLINE BOOL invert( const Matrix& rhs );

		// ret = v * matrix
		INLINE Vector3 preMult( const Vector3& v ) const;
		// ret = matrix * v
        INLINE Vector3 postMult( const Vector3& v ) const;
		// ret = matrix * v
        INLINE Vector3 operator* ( const Vector3& v ) const;
		// ret = v * matrix
        INLINE Vector4 preMult( const Vector4& v ) const;
		// ret = matrix * v
        INLINE Vector4 postMult( const Vector4& v ) const;
		// ret = matrix * v
        INLINE Vector4 operator* ( const Vector4& v ) const;

	public:
        // the scale matrix
        INLINE static Matrix makeScale( const Vector3& sv );
        INLINE static Matrix makeScale( F32 sx, F32 sy, F32 sz );		

		// the translate matrix
        INLINE static Matrix makeTranslate( const Vector3& dv );
        INLINE static Matrix makeTranslate( F32 x, F32 y, F32 z );		

		// the rotate matrix
        INLINE static Matrix makeRotate( const Vector3& from, const Vector3& to );
        INLINE static Matrix makeRotate( F32 angle, F32 x, F32 y, F32 z );
        INLINE static Matrix makeRotate( F32 angle, const Vector3& axis );
        INLINE static Matrix makeRotate( F32 angle1, const Vector3& axis1, 
										 F32 angle2, const Vector3& axis2,
										 F32 angle3, const Vector3& axis3 );
        INLINE static Matrix makeRotate( const Quaternion& quat );

		// make the inverse matrix
        INLINE static Matrix makeInverse( const Matrix& matrix );

		// make the orthonormal matrix
        INLINE static Matrix makeOrthonormal( const Matrix& matrix );
        
        // create an orthographic projection matrix. 
        INLINE static Matrix makeOrtho( F32 left, F32 right, F32 bottom, F32 top, F32 zNear, F32 zFar );

		// get the orthographic settings of the orthographic projection matrix. 		
        INLINE static BOOL getOrtho(const Matrix& matrix, F32& left, F32& right, F32& bottom, F32& top, F32& zNear, F32& zFar);

        // create a perspective projection. see glfrustum for further details.
        INLINE static Matrix makeFrustum( F32 left, F32 right, F32 bottom, F32 top, F32 zNear,  F32 zFar );

		// get the frustum settings of a perspective projection matrix.        
        INLINE static BOOL getFrustum( const Matrix& matrix, F32& left, F32& right, F32& bottom, F32& top, F32& zNear,  F32& zFar );

        // create a symmetrical perspective projection.
        INLINE static Matrix makePerspective( F32 fovy, F32 aspectRatio, F32 zNear, F32 zFar );

		// Get the frustum settings of a symmetric perspective projection
        //	matrix.
        //	Return FALSE if matrix is not a perspective matrix,
        //	where parameter values are undefined. 
		//	Note, if matrix is not a symmetric perspective matrix then the
		//	shear will be lost.
		//	Asymmetric matrices occur when stereo, power walls, caves and
		//	reality center display are used.
		//	In these configuration one should use the AsFrustum method instead.
        INLINE static BOOL getPerspective( const Matrix& matrix, F32& fovy,  F32& aspectRatio, F32& zNear, F32& zFar );

        //	Create the position and orientation as per a camera
        INLINE static Matrix makeLookAt( const Vector3& eye, const Vector3& center, const Vector3& up );

		//	Get to the position and orientation of a modelview matrix
        INLINE static VOID getLookAt( const Matrix& matrix, Vector3& eye,Vector3& center,Vector3& up, F32 lookDistance=1.0f );
        
        // apply a 3x3 transform of v*M[0..2,0..2].
        INLINE static Vector3 transform3x3( const Vector3& v,const Matrix& m );

        // apply a 3x3 transform of M[0..2,0..2]*v.
        INLINE static Vector3 transform3x3( const Matrix& m,const Vector3& v );

    protected:
        F32 _mat[4][4];
	};

	INLINE API Vector3 operator* (const Vector3& v, const Matrix& m );
	INLINE API Vector4 operator* (const Vector4& v, const Matrix& m );

//////////////////////////////////////////////////////////////////////////

NAMESPACE_END

//////////////////////////////////////////////////////////////////////////

#endif // __cplusplus

//////////////////////////////////////////////////////////////////////////

#endif

//////////////////////////////////////////////////////////////////////////